﻿using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Mountaineer.Netmf.Hardware;
using System;
using System.Threading;
using TI_BLE_HCI_ClientLib.Controllers.EnhancedControllers;
using TI_BLE_HCI_ClientLib.Controllers.GATT_Entities;

namespace TI_BLE_HCI_ClientLib_NETMF.Peripheral.Tester
{
    public class Program
    {
        const string DEVICE_NAME = "NETMF-GATT-Server";
        
        static GATTServerController _controller = new GATTServerController(Socket3.SerialPortName, 115200);
        static bool _buttonNotificationEnabled = false;
        static object _buttonNotificationEnabledLocker = new object();
        static bool _buttonIndicationEnabled = false;
        static object _buttonIndicationEnabledLocker = new object();
        static byte _valueR;
        static object _valueRLocker = new object();
        static byte _valueG;
        static object _valueGLocker = new object();
        static byte _valueB;
        static object _valueBLocker = new object();
        static PWM _pwmR = new PWM(OnboardIO.PwmRed, 100, 0, false);
        static PWM _pwmG = new PWM(OnboardIO.PwmGreen, 100, 0, false);
        static PWM _pwmB = new PWM(OnboardIO.PwmBlue, 100, 0, false);
        static InterruptPort _btn = new InterruptPort(OnboardIO.Button, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);

        public static byte ValueR
        {
            get
            {
                lock (_valueRLocker)
                {
                    return Program._valueR;
                }
            }
            set
            {
                lock (_valueRLocker)
                {
                    Program._valueR = value;
                    _pwmR.DutyCycle = value / 255.0;
                }
            }
        }

        public static byte ValueG
        {
            get
            {
                lock (_valueGLocker)
                {
                    return Program._valueG;
                }
            }
            set
            {
                lock (_valueGLocker)
                {
                    Program._valueG = value;
                    _pwmG.DutyCycle = value / 255.0;
                }
            }
        }

        public static byte ValueB
        {
            get
            {
                lock (_valueBLocker)
                {
                    return Program._valueB;
                }
            }
            set
            {
                lock (_valueBLocker)
                {
                    Program._valueB = value;
                    _pwmB.DutyCycle = value / 255.0;
                }
            }
        }

        

        static bool ButtonNotificationEnabled
        {
            get
            {
                lock (_buttonNotificationEnabledLocker)
                {
                    return Program._buttonNotificationEnabled;
                }
            }
            set
            {
                lock (_buttonNotificationEnabledLocker)
                {
                    Program._buttonNotificationEnabled = value;
                }
            }
        }

        static bool ButtonIndicationEnabled
        {
            get
            {
                lock (_buttonIndicationEnabledLocker)
                {
                    return Program._buttonIndicationEnabled;
                }
            }
            set
            {
                lock (_buttonIndicationEnabledLocker)
                {
                    Program._buttonIndicationEnabled = value;
                }
            }
        }

        public static void Main()
        {
            Debug.Print("Starting BLE controller...");

            _controller.Start(DEVICE_NAME);

            Debug.Print("Registering GATT services...");

            // ADD SERVICES
            var service1 = _controller.AddService(0xFFA0);

            service1.AddCharacteristic("LedR",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service1.AddCharacteristic("LedG",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service1.AddCharacteristic("LedB",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service1.AddCharacteristic("ButtonState",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Notify,
                GATT_Characteristic.ValueTypeEnum.Boolean);


            if (_controller.RegisterServices())
            {
                Debug.Print("...Succeeded.");
            }
            else
            {
                Debug.Print("...Failed!");
                return;
            }


            // REGISTER TO READ VALUE REQUESTS
            _controller.OnReadCharacteristicValue += _controller_OnReadCharacteristicValue;

            // REGISTER TO WRITE VALUE REQUESTS
            _controller.OnWriteCharacteristicValue += _controller_OnWriteCharacteristicValue;

            // REGISTER TO NOTIFICATION ENABLED CHANGED
            _controller.OnCharacteristicNotificationOrIndicationEnabledChanged += _controller_OnCharacteristicNotificationOrIndicationEnabledChanged;

            // REGISTER TO LINK STATE CHANGES
            _controller.OnLinkStateChanged += _controller_OnLinkStateChanged;

            // INIT PERIPHERALS
            initHardware();

            // MAKE DISCOVERABLE
            Debug.Print("Making Discoverable...");

            if (_controller.MakeDiscoverable())
            {
                Debug.Print("...Succeeded.");
            }
            else
            {
                Debug.Print("...Failed!");

                return;
            }

            // WAITING FOREVER...
            Debug.Print("Waiting for incoming connection...");

            Thread.Sleep(Timeout.Infinite);
        }

        
        private static void initHardware()
        {
            _pwmR.Start();
            _pwmG.Start();
            _pwmB.Start();

            _btn.OnInterrupt += _btn_OnInterrupt;
        }

        private static void uninitHardware()
        {
            _pwmR.DutyCycle = 0;
            _pwmG.DutyCycle = 0;
            _pwmB.DutyCycle = 0;

            _pwmR.Stop();
            _pwmG.Stop();
            _pwmB.Stop();

            _btn.OnInterrupt -= _btn_OnInterrupt;
        }


        static void _controller_OnLinkStateChanged(object s, GATTServerController.LinkStateEventArgs e)
        {
            if (e.State)
            {
                Debug.Print("Link ESTABLISHED");
            }
            else
            {
                Debug.Print("Link TERMINATED...waiting for incoming connection again...");

                if (_controller.MakeDiscoverable())
                {
                    Debug.Print("...Succeeded.");
                }
                else
                {
                    Debug.Print("...Failed!");
                    return;
                }
            }
        }

        static void _controller_OnReadCharacteristicValue(object s, GATTServerController.CharacteristicValueEventArgs e)
        {
            switch(e.Characteristic.Identifier)
            {
                case "LedR":
                    e.SetValue(ValueR);
                    break;

                case "LedG":
                    e.SetValue(ValueG);
                    break;

                case "LedB":
                    e.SetValue(ValueB);
                    break;

                case "ButtonState":
                    e.SetValue(_btn.Read());
                    break;
            }
        }

        static void _controller_OnWriteCharacteristicValue(object s, GATTServerController.CharacteristicValueEventArgs e)
        {
            switch (e.Characteristic.Identifier)
            {
                case "LedR":
                    ValueR = e.GetValueAsByte();
                    break;

                case "LedG":
                    ValueG = e.GetValueAsByte();
                    break;

                case "LedB":
                    ValueB = e.GetValueAsByte();
                    break;
            }
        }

        static void _btn_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            if (ButtonNotificationEnabled)
            {

                try
                {
                    if (_controller.RaiseNotification("ButtonState", data2 != 0))
                    {
                        Debug.Print("Notification raising Succeeded");
                    }
                    else
                    {
                        Debug.Print("Notification raising Failed");
                    }
                }
                catch { }
            }

            if (ButtonIndicationEnabled)
            {

                try
                {
                    if (_controller.RaiseIndication("ButtonState", data2 != 0))
                    {
                        Debug.Print("Indication raising Succeeded");
                    }
                    else
                    {
                        Debug.Print("Indication raising Failed");
                    }
                }
                catch { }
            }
        }

        static void _controller_OnCharacteristicNotificationOrIndicationEnabledChanged(object s, GATTServerController.CharacteristicNotificationOrIndicationEnabledEventArgs e)
        {
            switch (e.Characteristic.Identifier)
            {
                case "ButtonState":
                    ButtonNotificationEnabled = e.NotificationState;
                    ButtonIndicationEnabled = e.IndicationState;
                    break;
            }
        }

    }
}
